package com.wecan.es.learning.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.yyh.elasticsearch.entity.Good;
import com.yyh.elasticsearch.repository.GoodsRepository;
import com.yyh.elasticsearch.service.GoodService;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class GoodServiceImpl implements GoodService {
    @Autowired
    private GoodsRepository goodsRepository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public void saveGoods(Good good) {
        goodsRepository.save(good);
    }

    @Override
    public JSONObject findAll() {
        JSONObject object = new JSONObject();
        List<Good> goodList = new ArrayList<>();
        goodsRepository.findAll().forEach(good -> {
            goodList.add(good);
        });
        object.put("data", goodList);
        return object;
    }

    @Override
    public void deleteGoodById(Long id) {
        goodsRepository.deleteById(id);
    }

    @Override
    public void updateGoods(Good goodinfo) {
        goodsRepository.save(goodinfo);

    }

    @Override
    public JSONObject queryListByPage(Integer pageNum, Integer pageSize, String query) {
        List<Good> resultList = new ArrayList<>();
        JSONObject jsonObject = new JSONObject();
        if (pageNum == null) pageNum = 0;
        Pageable pageable = new PageRequest(pageNum, pageSize);
        QueryStringQueryBuilder builder = new QueryStringQueryBuilder(query);
        SearchQuery searchQuery = new NativeSearchQueryBuilder().withPageable(pageable).withQuery(builder).build();
        goodsRepository.search(searchQuery).forEach(resultList::add);
        jsonObject.put("data", resultList);
        return jsonObject;
    }

    @Override
    public JSONObject searchContent(String searchContent) {
        List<Good> goodList = new ArrayList<>();
        JSONObject jsonObject = new JSONObject();
        QueryStringQueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder(searchContent);
        goodsRepository.search(queryStringQueryBuilder).forEach(goodList::add);
        jsonObject.put("data", goodList);
        return jsonObject;
    }

    @Override
    public JSONObject searchComplexByCondition(String title, String brand, Integer pageNum, Integer pageSize, String sort) {
        List<Good> goodList = new ArrayList<>();
        JSONObject jsonObject = new JSONObject();
        //1.创建QueryBuilder(即设置查询条件)这儿创建的是组合查询(也叫多条件查询),后面会介绍更多的查询方法
        /*组合查询BoolQueryBuilder
         * must(QueryBuilders)   :AND
         * mustNot(QueryBuilders):NOT
         * should:               :OR
         * */
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        /**
         * //builder下有must、should以及mustNot 相当于sql中的and、or以及not
         * //设置模糊搜索,title 含有学习两个字
         */
        builder.must(QueryBuilders.fuzzyQuery("title", title));

        builder.must(new QueryStringQueryBuilder("brand").field(brand));
        //根据价格进行排序
        FieldSortBuilder sortBuilder = null;
        if ("desc".equals(sort)) {
            sortBuilder = SortBuilders.fieldSort("price").order(SortOrder.DESC);
        } else {
            sortBuilder = SortBuilders.fieldSort("price").order(SortOrder.ASC);
        }
        //设置分页(从第一页开始，一页显示10条)
        //注意开始是从0开始，有点类似sql中的方法limit 的查询
        PageRequest pageRequest = new PageRequest(pageNum, pageSize);
        //2、构建查询
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //将所有查询条件放
        nativeSearchQueryBuilder.withQuery(builder);
        //将分页条件放到
        nativeSearchQueryBuilder.withPageable(pageRequest);
        //将排序放置到构建中
        nativeSearchQueryBuilder.withSort(sortBuilder);
        NativeSearchQuery query = nativeSearchQueryBuilder.build();
        //3、执行查询
        Page<Good> search = goodsRepository.search(query);
//        List<Good> goodList1 = elasticsearchTemplate.queryForList(query, Good.class);
        search.forEach(goodList::add);
        jsonObject.put("data", goodList);
        return jsonObject;
    }

    @Override
    public List<Map<String, Object>> queryHit(String keyword, String indexName, String... fieldNames) {
        //构造查询条件，使用分词器
        QueryBuilder matchBuilder = createQueryBuilder(keyword, fieldNames);
        // 设置高亮,使用默认的highlighter高亮器
        HighlightBuilder highlighter = createHighlightBuilder(fieldNames);
        SearchResponse searchResponse = elasticsearchTemplate.getClient().prepareSearch(indexName)
                .setQuery(matchBuilder)
                .highlighter(highlighter)
                .setSize(10000) // 设置一次返回的文档数量，最大值：10000
                .get();
        //返回搜索结果
        SearchHits hits = searchResponse.getHits();
        return getHitList(hits);
    }

    @Override
    public JSONObject searchByPinyin(String brand) {
        JSONObject jsonObject = new JSONObject();
        List<Good> resultList = new ArrayList<>();
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(QueryBuilders.matchPhraseQuery("brand", brand).analyzer("pinyin_analyzer"));
        Page<Good> goods = goodsRepository.search(queryBuilder.build());
        if (goods != null)
            goods.forEach(resultList::add);
        jsonObject.put("data", resultList);
        return jsonObject;
    }

    /**
     * @param
     * @return
     * @Title
     * @Description: 构造高亮器
     * @author yaoyonghao
     * @date 2019/3/5 15:09
     */
    private HighlightBuilder createHighlightBuilder(String... fieldNames) {
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                .preTags("<span style='color:red'>")
                .postTags("</span>");
        // 设置高亮字段
        for (String fieldName : fieldNames) highlightBuilder.field(fieldName);
        return highlightBuilder;
    }

    /**
     * @param keyword    关键字
     * @param fieldNames 查询的字段
     * @return
     * @Title
     * @Description: 构造查询条件
     * @author yaoyonghao
     * @date 2019/3/5 15:05
     */
    private QueryBuilder createQueryBuilder(String keyword, String... fieldNames) {
        // matchQuery(),单字段搜索
        // 构造查询条件,使用标准分词器.
        return QueryBuilders.multiMatchQuery(keyword, fieldNames)
                .analyzer("ik_max_word")
                .operator(Operator.OR);

    }

    private List<Map<String, Object>> getHitList(SearchHits hits) {
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map;
        for (SearchHit searchHit : hits) {
            map = new HashMap<>();
            // 处理源数据
            map.put("source", searchHit.getSourceAsMap());
            // 处理高亮数据
            Map<String, Object> hitMap = new HashMap<>();
            searchHit.getHighlightFields().forEach((k, v) -> {
                String hight = "";
                for (Text text : v.getFragments()) hight += text.string();
                hitMap.put(v.getName(), hight);
            });
            map.put("highlight", hitMap);
            list.add(map);
        }
        return list;
    }
}